package com.xingbg.projectimpl.config.dubbo;

import org.apache.dubbo.config.spring.beans.factory.annotation.ServiceClassPostProcessor;
import org.apache.dubbo.config.spring.context.DubboBootstrapApplicationListener;
import org.apache.dubbo.config.spring.context.DubboLifecycleComponentApplicationListener;
import org.apache.dubbo.config.spring.context.annotation.EnableDubboConfig;
import org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration;
import org.apache.dubbo.spring.boot.autoconfigure.DubboConfigurationProperties;
import org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBindingAutoConfiguration;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Set;

/**
 * 重新自动配置@DubboService.
 *
 */
@ConditionalOnClass(name = "org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration")
@ConditionalOnProperty(
        prefix = "dubbo",
        name = {"enabled"},
        matchIfMissing = true
)
@Configuration
@AutoConfigureAfter({DubboRelaxedBindingAutoConfiguration.class})
@EnableConfigurationProperties({DubboConfigurationProperties.class})
@EnableDubboConfig
@EnableAutoConfiguration(excludeName = "org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration")
public class MyDubboAutoConfiguration implements ApplicationContextAware, BeanDefinitionRegistryPostProcessor {
    public MyDubboAutoConfiguration() {
    }

    @ConditionalOnProperty(
            prefix = "dubbo.scan.",
            name = {"base-packages"}
    )
    @ConditionalOnBean(
            name = {"dubbo-service-class-base-packages"}
    )
    @Bean
    public ServiceClassPostProcessor serviceClassPostProcessor(@Qualifier("dubbo-service-class-base-packages") Set<String> packagesToScan) {
        return new MyServiceClassPostProcessor(packagesToScan);
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (applicationContext instanceof ConfigurableApplicationContext) {
            ConfigurableApplicationContext context = (ConfigurableApplicationContext)applicationContext;
            DubboLifecycleComponentApplicationListener dubboLifecycleComponentApplicationListener = new DubboLifecycleComponentApplicationListener();
            dubboLifecycleComponentApplicationListener.setApplicationContext(applicationContext);
            context.addApplicationListener(dubboLifecycleComponentApplicationListener);
            DubboBootstrapApplicationListener dubboBootstrapApplicationListener = new DubboBootstrapApplicationListener();
            dubboBootstrapApplicationListener.setApplicationContext(applicationContext);
            context.addApplicationListener(dubboBootstrapApplicationListener);
        }

    }

    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        this.removeBeanDefinition(registry, "dubboLifecycleComponentApplicationListener");
        this.removeBeanDefinition(registry, "dubboBootstrapApplicationListener");
    }

    private void removeBeanDefinition(BeanDefinitionRegistry registry, String beanName) {
        if (registry.containsBeanDefinition(beanName)) {
            registry.removeBeanDefinition(beanName);
        }

    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    }
}
